package admin

import (
	"night-school-api/database"
	"night-school-api/job"
	"night-school-api/models"
	"night-school-api/utils"

	"fmt"
	"os"
	"strconv"
	"time"

	"github.com/labstack/echo/v4"
)

var JobQueue *job.JobQueue

type updateCourseStatusRequest struct {
	ID     int                `json:"id" gorm:"-" validate:"required,gte=1"`
	Status models.AuditStatus `json:"status" gorm:"column:status;" validate:"required,gte=0,lte=2"`
}

type updateCourseRequest struct {
	ID     int    `json:"id" gorm:"-" validate:"required,gte=1"`
	CateId int    `json:"cate_id" validate:"required,gte=1" gorm:"column:cate_id;"`
	Name   string `json:"name" validate:"required,min=1,max=64" gorm:"column:name;"`

	TeacherName        string `json:"teacher_name" validate:"required,min=1,max=64" gorm:"column:teacher_name;"`
	TeacherDescription string `json:"teacher_description" validate:"required,min=1,max=255" gorm:"column:teacher_description;"`
	TeacherOrg         string `json:"teacher_org" validate:"max=64" gorm:"column:teacher_org;"`
	TeacherContact     string `json:"teacher_contact" validate:"required,max=64" gorm:"column:teacher_contact;"`

	Introduction string                   `json:"introduction" validate:"required,min=1,max=255" gorm:"column:introduction;"`
	IsNonProfit  int                      `json:"is_non_profit" validate:"gte=0,lte=1" gorm:"column:is_non_profit;"`
	EnrollEndAt  models.JSONTimeNoSeconds `json:"enroll_end_at" validate:"required,jsontime_no_seconds" gorm:"column:enroll_end_at;type:datetime"`
	StartAt      models.JSONTimeNoSeconds `json:"start_at" validate:"-" gorm:"column:start_at;type:datetime"`
}

func GetCourses(c echo.Context) error {

	// 审核状态
	status, err := strconv.Atoi(c.QueryParam("status"))
	if err != nil {
		status = -1
	}
	if status < -1 || status > 2 {
		return utils.JSONError(c, "参数错误")
	}

	// 分类id
	cateId, err := strconv.Atoi(c.QueryParam("cate_id"))
	if err != nil {
		cateId = 0
	}

	// 县级区划索引
	countyIndex, err := strconv.Atoi(c.QueryParam("county_index"))
	if err != nil {
		countyIndex = -1
	} else {
		if countyIndex < 0 || countyIndex >= len(utils.Counties) {
			countyIndex = -1
		}
	}

	keywords := c.QueryParam("keywords")
	hot := c.QueryParam("hot")

	db := database.DB

	query := db.Model(&models.Course{})
	if status != -1 {
		query = query.Where("status = ?", status)
	}
	if cateId > 0 {
		query = query.Where("cateId = ?", cateId)
	}
	if countyIndex > 0 {
		query = query.Where("county_index =?", countyIndex)
	}

	if keywords != "" {
		// 使用关键字搜索时，显示未结束和已结束的课程
		query = query.Where(
			db.Where("name LIKE ?", "%"+keywords+"%").Or("introduction LIKE?", "%"+keywords+"%"),
		)
	}

	var order string
	if hot == "yes" {
		order = "enroll_amount DESC"
	} else {
		order = "status ASC, id DESC"
	}

	var total int64
	var courses []models.CourseWithEnrollmentAndComment
	query.Count(&total)
	page, size := utils.GetPagination(c)
	query.Preload("CourseCategory").Order(order).Limit(size).Offset((page - 1) * size).Find(&courses)

	var (
		unhandled_comment_amount int64
		comment_amount           int64

		unhandled_enrollment_amount int64
	)

	for i := range courses {
		course := courses[i]
		db.Model(&models.Comment{}).Where("course_id =?", course.ID).Count(&comment_amount)
		db.Model(&models.Comment{}).Where("course_id =? AND status =?", course.ID, 0).Count(&unhandled_comment_amount)

		courses[i].Comment.Count = int(comment_amount)
		courses[i].Comment.UnhandledCount = int(unhandled_comment_amount)

		db.Model(&models.Enrollment{}).Where("course_id =? AND status =?", course.ID, 0).Count(&unhandled_enrollment_amount)

		courses[i].Enrollment.Count = int(course.EnrollAmount)
		courses[i].Enrollment.UnhandledCount = int(unhandled_enrollment_amount)
	}

	return utils.JSONPagination(c, page, size, total, courses)
}

func UpdateCourseStatus(c echo.Context) error {

	var req updateCourseStatusRequest

	if err := c.Bind(&req); err != nil {
		return utils.JSONError(c, "请求参数错误")
	}

	db := database.DB
	var course models.Course
	db.First(&course, req.ID)

	if course.ID <= 0 {
		return utils.JSONError(c, "操作失败，请刷新重试")
	}

	// c.Logger().Info(fmt.Sprintf("req: %v", req))

	statusChanged := false
	if course.Status != req.Status {
		statusChanged = true
	}

	err := db.Model(&course).Updates(map[string]interface{}{"status": req.Status}).Error

	if err != nil {
		c.Logger().Info("修改课程失败: " + err.Error())
		return utils.JSONError(c, "修改课程失败")
	} else {

		if statusChanged && course.Status == models.AuditApproved {

			// 给老师发送课程审核通过的订阅消息
			if course.IsSubscribed == 1 {

				var user models.User
				db.First(&user, course.UserID)

				if len(user.Openid) > 0 {

					statuZh := "已审核通过"

					err = utils.CourseAuditApprovedSendMsg(c, course.ID, user.Openid, course.Name, statuZh)
					c.Logger().Info(fmt.Sprintf("CourseAuditApprovedSendMsg() err: %#v", err))
				}
			}

			// 创建定时任务， 开课前一天给学生发送开课提醒订阅消息
			taskID := "course_start:" + strconv.Itoa(course.ID)
			sendTime := course.StartAt.Add(-24 * time.Hour)
			momentLater := time.Now().In(models.TimeLocation).Add(20 * time.Second)

			if sendTime.Before(momentLater) {
				sendTime = momentLater
			}

			c.Logger().Info(fmt.Sprintf("课程（id %d ）开课提醒时间：: %s \n", course.ID, sendTime.Format("2006-01-02 15:04:05")))

			err = JobQueue.CreateCourseStartJob(c.Request().Context(), taskID, sendTime)
			if err != nil {
				c.Logger().Info(fmt.Sprintf("创建课程开始提醒的定时任务错误 err: %#v \n %s \n", err, err.Error()))
			}
		}

		return utils.JSONSuccess(c, nil, "修改课程成功")
	}
}

func UpdateCourse(c echo.Context) error {

	var req updateCourseRequest

	if err := c.Bind(&req); err != nil {
		return utils.JSONError(c, "请求参数错误")
	}

	db := database.DB
	var course models.Course
	db.First(&course, req.ID)

	if course.ID <= 0 {
		return utils.JSONError(c, "操作失败，请刷新重试")
	}

	c.Logger().Info(fmt.Sprintf("req: %#v", req))

	err := db.Model(&course).Updates(req).Error

	if err != nil {
		c.Logger().Info("修改课程失败: " + err.Error())
		return utils.JSONError(c, "修改课程失败")
	} else {
		return utils.JSONSuccess(c, nil, "修改课程成功")
	}
}

// 上传封面
func UploadCover(c echo.Context) error {
	var req map[string]interface{}

	if err := c.Bind(&req); err != nil {
		return utils.JSONError(c, "请求参数错误")
	}

	var courseId int
	courseIdStr, ok := req["course_id"].(string)
	if !ok {
		return utils.JSONError(c, "请求参数错误")
	} else {
		if id, err := strconv.Atoi(courseIdStr); err == nil {
			courseId = id
		}
	}

	if courseId <= 0 {
		return utils.JSONError(c, "id错误")
	}

	// Source
	file, err := c.FormFile("file")
	if err != nil {
		return utils.JSONError(c, "上传图片失败: "+err.Error())
	}

	// Validate image
	isValid, err := utils.IsValidImage(file)
	if !isValid {
		return utils.JSONError(c, "图片文件格式错误: "+err.Error())
	}

	// Destination
	s := strconv.Itoa(courseId) + " " + strconv.FormatInt(time.Now().Unix(), 10)
	dstFilename := utils.SubdirFilepath(s, "./uploads/cover/", file.Filename)

	// c.Logger().Info("dstFilename:" + dstFilename)
	// c.Logger().Info("file.Filename:" + file.Filename)

	src, err := file.Open()
	if err != nil {
		return utils.JSONError(c, "上传图片失败: "+"Failed to open file")
	}
	defer src.Close()

	dst, err := os.Create(dstFilename)
	if err != nil {
		return utils.JSONError(c, "上传图片失败: "+"Failed to create file")
	}
	defer dst.Close()

	if _, err = dst.ReadFrom(src); err != nil {
		return utils.JSONError(c, "上传图片失败: "+"Failed to save file")
	}

	err = utils.ScaleImage(dstFilename, 800, 800)
	if err != nil {
		return utils.JSONError(c, "上传图片失败: "+err.Error())
	}

	// 去除路径前缀 uploads
	// c.Logger().Info("dstFilename:" + dstFilename)
	cover := utils.TrimTopParentPath(dstFilename)
	// c.Logger().Info("cover:" + cover)

	db := database.DB
	// var course models.Course
	coverMap := map[string]interface{}{}
	// db.Model(&course).First(&course, courseId)
	db.Model(&models.Course{}).Select("cover").First(&coverMap, courseId)
	c.Logger().Info(fmt.Sprintf("coverMap: %#v", coverMap))
	oldImg, ok := coverMap["cover"].(string)
	if !ok {
		oldImg = ""
	}

	rs := db.Model(&models.Course{}).Where("id = ?", courseId).Update("cover", cover)
	if rs.Error != nil {
		return utils.JSONError(c, "更新课程封面图片失败"+rs.Error.Error())
	}

	// 删除旧的图片文件
	if oldImg != "" {
		// c.Logger().Info("oldImg: " + oldImg)
		oldImgPath := "./uploads/" + oldImg
		c.Logger().Info("oldImgPath: " + oldImgPath)
		if utils.FileExists(oldImgPath) {
			err := os.Remove(oldImgPath)
			if err != nil {
				c.Logger().Info("删除旧的图片文件失败: " + err.Error())
			} else {
				c.Logger().Info("删除旧的图片文件成功: " + oldImgPath)
			}
		}
	}

	return utils.JSONSuccess(c, nil, "上传图片成功")
}

func DeleteCourse(c echo.Context) error {

	var req updateCourseRequest

	if err := c.Bind(&req); err != nil {
		return utils.JSONError(c, "请求参数错误")
	}

	db := database.DB
	var course models.Course
	db.First(&course, req.ID)

	if course.ID <= 0 {
		return utils.JSONError(c, "操作失败，请刷新重试")
	}

	// c.Logger().Info(fmt.Sprintf("req: %v", req))

	err := db.Delete(&course).Error

	if err != nil {
		c.Logger().Info("删除课程失败: " + err.Error())
		return utils.JSONError(c, "删除课程失败")
	} else {

		if course.Status == models.AuditApproved {

			// 取消开课提醒订阅消息的定时任务
			taskID := "course_start:" + strconv.Itoa(course.ID)
			err = JobQueue.CancelCourseStartJob(c.Request().Context(), taskID)
			if err != nil {
				c.Logger().Info(fmt.Sprintf("取消课程开始提醒的定时任务错误 err: %#v \n %s \n", err, err.Error()))
			}
		}

		return utils.JSONSuccess(c, nil, "删除课程成功")
	}
}
